#pragma once
#include "App/Property.h"
#include "App/ObjectIdentifier.h"
#include "TopoDS_Shape.hxx"
namespace Base {
    class  Uuid{};
}
namespace Part {
    class Feature;

}

namespace Base {
    class Placement;
}
namespace App {
    class Enumeration{};
    enum class LinkScope {
        Local,
        Child,
        Global,
        Hidden,
    };
    class Expression {
    public:
    };
    class ObjectIdentifier;

    // class PropertyXLinkContainer {};
    // class PropertyExpressionContainer : public App::PropertyXLinkContainer{};
    class PropertyExpressionContainer{};
    class  PropertyLinkBase : public Property
    {
        TYPESYSTEM_HEADER_WITH_OVERRIDE();
    public:
        void getLinks(const std::vector<DocumentObject*>& res, bool no_hidden) {}
        void getLinks(const std::vector<DocumentObject*>& res) {}
        PropertyLinkBase* adjustLink(const std::set<App::DocumentObject*>& set) { return nullptr; }
    };
    class PropertyExpressionEngine: public PropertyLinkBase {
    public:
        struct ExpressionInfo{
            bool expression = false;
        };

        inline void setValue(){}
        inline bool isTouched(void) const {
            return false;
        }
        inline void getLinks(const std::vector<DocumentObject*>& res) const{}
        std::map<App::ObjectIdentifier, const App::Expression*> 
            inline  getExpressions() const
        {
            std::map<App::ObjectIdentifier, const Expression*> res;
            return res;
        }
        inline void setValue(const ObjectIdentifier & path, std::shared_ptr<Expression> expr){}
  /*      inline const boost::any getPathValue(const App::ObjectIdentifier& path) const {
            return boost::any();
        }*/
        inline void renameObjectIdentifiers(const std::map<ObjectIdentifier, ObjectIdentifier> &paths){}
        inline  virtual void Save(Base::Writer& writer) const {}
        inline   virtual void Restore(Base::XMLReader& reader) {}

        inline  virtual Property* Copy(void) const { return nullptr; }
        inline  virtual void Paste(const Property& from) {}
    };

    class PropertyLinkSubList : public App::PropertyLinkBase{
        TYPESYSTEM_HEADER_WITH_OVERRIDE();
    public:
        DocumentObject * getValue(){return nullptr;}
        std::vector<App::DocumentObject*> getValues() {
            return std::vector<App::DocumentObject*>();
        }

        bool isTouched() const{return false;}
        std::vector<std::string> getSubValues(){return std::vector<std::string>();}
        int getSize(){return 1;}
        void setValues(const std::vector<DocumentObject*>& vector, const std::vector<std::string>& sub_elements){}
        void setValue(DocumentObject*, const char*) {}
        inline  virtual void Save(Base::Writer& writer) const {}
        inline   virtual void Restore(Base::XMLReader& reader) {}

        inline  virtual Property* Copy(void) const { return nullptr; }
        inline  virtual void Paste(const Property& from) {}
    };
    class PropertyLinkSub{
    public:
        DocumentObject* getValue(){return nullptr;}
    };
    struct CStringHasher {
        inline std::size_t operator()(const char *s) const {
            if(!s) return 0;
            return boost::hash_range(s,s+std::strlen(s));
        }
        inline bool operator()(const char *a, const char *b) const {
            if(!a) return !b;
            if(!b) return false;
            return std::strcmp(a,b)==0;
        }
    };

    class PropertyLink {
    public:
        void setValue(){}
        void setValue(App::DocumentObject * lValue)
        {}
        bool getValue(){return false;}
        // void setContainer(__resharper_unknown_type* fillet_base){}
    };
    class PropertyLinkList : public Property {
    public:
        void setValue(std::nullptr_t null){}
        void setScope(LinkScope child){}

        std::vector<DocumentObject*> getValues() const{
            return std::vector<DocumentObject*>();
        }

        void setValues(const std::vector<DocumentObject*>& grp){}
        int getSize(){return 0;}
        inline  virtual void Save(Base::Writer& writer) const {}
        inline   virtual void Restore(Base::XMLReader& reader) {}

        inline  virtual Property* Copy(void) const { return nullptr; }
        inline  virtual void Paste(const Property& from) {}
    };

    class  PropertyLength :public App::Property
{
    TYPESYSTEM_HEADER();
    public:
    PropertyLength(void){}
    virtual ~PropertyLength(){}
    void setValue(double lValue) { }

    double getValue(void) const{return  1.0;}

        virtual const char* getEditorName(void) const { return "Gui::PropertyEditor::PropertyFloatItem"; }

        virtual PyObject *getPyObject(void){return nullptr;}
    virtual void setPyObject(PyObject*) { }

    virtual void Save(Base::Writer& writer) const { }

    virtual void Restore(Base::XMLReader& reader) { }

    virtual Property *Copy(void) const{return nullptr;}
    virtual void Paste(const Property& from) { }

    virtual unsigned int getMemSize (void) const{return sizeof(double);}

    void setPathValue(const App::ObjectIdentifier& path, const boost::any& value) { }

    const boost::any getPathValue(const App::ObjectIdentifier& path) const {return boost::any(); }

    virtual bool isSame(const Property &other) const {
            if (&other == this)
                return true;
            return getTypeId() == other.getTypeId()
                && getValue() == static_cast<decltype(this)>(&other)->getValue();
        }

    protected:
        double _dValue;
};
    class  PropertyQuantityConstraint : public Property
    {
        TYPESYSTEM_HEADER();

    public:
        PropertyQuantityConstraint(void):_ConstStruct(nullptr){}
        virtual ~PropertyQuantityConstraint(){}

        /// Constraint methods
        //@{
        /// the boundary struct
        struct Constraints {
            double LowerBound, UpperBound, StepSize;
        };
        /** setting the boundaries
         * This sets the constraint struct. It can be dynamically
         * allocated or set as an static in the class the property
         * belongs to:
         * \code
         * const Constraints percent = {0.0,100.0,1.0}
         * \endcode
         */
        void setConstraints(const Constraints* sConstrain){}
        /// get the constraint struct
        const Constraints*  getConstraints(void) const{return nullptr;}
        //@}

        double getMinimum() const{return 1.0;}
        double getMaximum() const{return 1.0;}
        double getStepSize() const{return 1.0;}

        virtual const char* getEditorName(void) const{return nullptr;}
        inline  virtual void Save (Base::Writer &writer) const{}
        inline  virtual void Restore(Base::XMLReader &reader){}

        inline  virtual Property *Copy(void) const{return nullptr;}
        inline  virtual void Paste(const Property &from){}


    protected:
        const Constraints* _ConstStruct;
    };
    class  PropertyAngle: public PropertyQuantityConstraint
    {
        TYPESYSTEM_HEADER();
    public:
        PropertyAngle(void){}
        virtual ~PropertyAngle(){}
        virtual const char* getEditorName(void) const { return "Gui::PropertyEditor::PropertyAngleItem"; }
        double getValue(void) const { return 1.0; }

    };
    
    /** Frequency property
     * This is a property for representing frequency. It is basically a float
     * property. On the Gui it has a quantity like 1/s or Hz.
     */
    class  PropertyFrequency: public Property
    {
        TYPESYSTEM_HEADER();
    public:
        inline  virtual void Save (Base::Writer &writer) const{}
        inline   virtual void Restore(Base::XMLReader &reader){}

        inline  virtual Property *Copy(void) const{return nullptr;}
        inline  virtual void Paste(const Property &from){}
        inline   PropertyFrequency(void){}
        inline  virtual ~PropertyFrequency(){}
    };
    class PropertyPythonObject : public Property
    {
        TYPESYSTEM_HEADER();

        public:
            inline   PropertyPythonObject(void){}
            inline  virtual ~PropertyPythonObject(){}

            inline  void setValue(Py::Object){}
            inline  Py::Object getValue() const{return Py::Object();}

            inline  virtual PyObject *getPyObject(void){return nullptr;}
            inline virtual void setPyObject(PyObject *){}

        /** Use Python's pickle module to save the object */
            inline  virtual void Save (Base::Writer &writer) const{}
        /** Use Python's pickle module to restore the object */
            inline  virtual void Restore(Base::XMLReader &reader){}
            inline  virtual void SaveDocFile (Base::Writer &writer) const{}
            inline  virtual void RestoreDocFile(Base::Reader &reader){}

            inline  virtual unsigned int getMemSize (void) const{return 0;}
            inline  virtual Property *Copy(void) const{return nullptr;}
            inline  virtual void Paste(const Property &from){}

            inline  std::string toString() const{return std::string();}
            inline  void fromString(const std::string&){}

        private:
            inline  void saveObject(Base::Writer &writer) const{}
            inline  void restoreObject(Base::XMLReader &reader){}
            inline  std::string encodeValue(const std::string& str) const{return std::string();}
            inline  std::string decodeValue(const std::string& str) const{return std::string();}
            inline  void loadPickle(const std::string& str){}
        Py::Object object;
    };
}
namespace Part {
    class Geometry;
}
